#include "hal.h"
#include "pic.h"
#include "pit.h"

#include "vga_text.h"

#define		I86_PIT_REG_COUNTER0		0x40
#define		I86_PIT_REG_COUNTER1		0x41
#define		I86_PIT_REG_COUNTER2		0x42
#define		I86_PIT_REG_COMMAND			0x43

static volatile uint32_t _tickCounts = 0;
static bool isPitInit = false;

//! read data from counter
uint8_t i86_pit_read_data (uint16_t counter) {

	uint8_t	port= (counter==I86_PIT_OCW_COUNTER_0) ? I86_PIT_REG_COUNTER0 :
		((counter==I86_PIT_OCW_COUNTER_1) ? I86_PIT_REG_COUNTER1 : I86_PIT_REG_COUNTER2);

	return inportb (port);
}


//! send data to a counter
void i86_pit_send_data (uint16_t data, uint8_t counter) {

	uint8_t	port= (counter==I86_PIT_OCW_COUNTER_0) ? I86_PIT_REG_COUNTER0 :
		((counter==I86_PIT_OCW_COUNTER_1) ? I86_PIT_REG_COUNTER1 : I86_PIT_REG_COUNTER2);

	outportb (port, (uint8_t)data);
}


//! send command to pit
void i86_pit_send_command (uint8_t cmd) {

	outportb (I86_PIT_REG_COMMAND, cmd);
}

//! starts a counter
void i86_pit_start_counter (uint32_t freq, uint8_t counter, uint8_t mode) {

	if (freq==0)
		return;

	uint16_t divisor = uint16_t(1193181 / (uint16_t)freq);

	//! send operational command
	uint8_t ocw=0;
	ocw = (ocw & ~I86_PIT_OCW_MASK_MODE) | mode;
	ocw = (ocw & ~I86_PIT_OCW_MASK_RL) | I86_PIT_OCW_RL_DATA;
	ocw = (ocw & ~I86_PIT_OCW_MASK_COUNTER) | counter;
	i86_pit_send_command (ocw);

	//! set frequency rate
	i86_pit_send_data (divisor & 0xff, 0);
	i86_pit_send_data ((divisor >> 8) & 0xff, 0);

	//! reset tick count
	_tickCounts = 0;
}

void _cdecl i86_pit_hanlder()
{
	_asm add esp, 12
	_asm cli
	_asm pushad

	_tickCounts++;

	interrupt_done(0);

	_asm popad
	_asm sti
	_asm iretd
}

uint32_t i86_set_ticks(uint32_t ticks)
{
	uint32_t returnValue = _tickCounts;
	_tickCounts = ticks;
	return returnValue;
}

uint32_t i86_get_ticks()
{
	return _tickCounts;
}

void i86_pit_initialize()
{
	setvect(32,i86_pit_hanlder);
	isPitInit = true;
}